home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / osi / isode / dosisode / DOSISODE80.ZIP / ISODE8.WRK / UNIX / LIB / DNS / RES_QUER.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-16  |  7.8 KB  |  273 lines

  1. #include <fiddle.h>
  2. /*
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that: (1) source distributions retain this entire copyright
  8.  * notice and comment, and (2) distributions including binaries display
  9.  * the following acknowledgement:  ``This product includes software
  10.  * developed by the University of California, Berkeley and its contributors''
  11.  * in the documentation or other materials provided with the distribution
  12.  * and in all advertising materials mentioning features or use of this
  13.  * software. Neither the name of the University nor the names of its
  14.  * contributors may be used to endorse or promote products derived
  15.  * from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #if defined(LIBC_SCCS) && !defined(lint)
  22. static char sccsid[] = "@(#)res_query.c    5.7 (Berkeley) 6/1/90";
  23. #endif /* LIBC_SCCS and not lint */
  24.  
  25. #include <sys/param.h>
  26. #include <sys/socket.h>
  27. #include <netinet/in.h>
  28. #include <ctype.h>
  29. #include <netdb.h>
  30. #include <stdio.h>
  31. #include <errno.h>
  32. #include <string.h>
  33. #include <arpa/inet.h>
  34. #include <arpa/nameser.h>
  35. #include <resolv.h>
  36.  
  37. #if PACKETSZ > 1024
  38. #define MAXPACKET    PACKETSZ
  39. #else
  40. #define MAXPACKET    1024
  41. #endif
  42.  
  43. extern int errno;
  44. int h_errno;
  45.  
  46. /*
  47.  * Formulate a normal query, send, and await answer.
  48.  * Returned answer is placed in supplied buffer "answer".
  49.  * Perform preliminary check of answer, returning success only
  50.  * if no error is indicated and the answer count is nonzero.
  51.  * Return the size of the response on success, -1 on error.
  52.  * Error number is left in h_errno.
  53.  * Caller must parse answer and determine whether it answers the question.
  54.  */
  55. res_query(name, class, type, answer, anslen)
  56.     char *name;        /* domain name */
  57.     int class, type;    /* class and type of query */
  58.     u_char *answer;        /* buffer to put answer */
  59.     int anslen;        /* size of answer buffer */
  60. {
  61.     char buf[MAXPACKET];
  62.     HEADER *hp;
  63.     int n;
  64.  
  65.     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  66.         return (-1);
  67. #ifdef DEBUG
  68.     if (_res.options & RES_DEBUG)
  69.         printf("res_query(%s, %d, %d)\n", name, class, type);
  70. #endif
  71.     n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
  72.         buf, sizeof(buf));
  73.  
  74.     if (n <= 0) {
  75. #ifdef DEBUG
  76.         if (_res.options & RES_DEBUG)
  77.             printf("res_query: mkquery failed\n");
  78. #endif
  79.         h_errno = NO_RECOVERY;
  80.         return (n);
  81.     }
  82.     n = res_send(buf, n, answer, anslen);
  83.     if (n < 0) {
  84. #ifdef DEBUG
  85.         if (_res.options & RES_DEBUG)
  86.             printf("res_query: send error\n");
  87. #endif
  88.         h_errno = TRY_AGAIN;
  89.         return(n);
  90.     }
  91.  
  92.     hp = (HEADER *) answer;
  93.     if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
  94. #ifdef DEBUG
  95.         if (_res.options & RES_DEBUG)
  96.             printf("rcode = %d, ancount=%d\n", hp->rcode,
  97.                 ntohs(hp->ancount));
  98. #endif
  99.         switch (hp->rcode) {
  100.             case NXDOMAIN:
  101.                 h_errno = HOST_NOT_FOUND;
  102.                 break;
  103.             case SERVFAIL:
  104.                 h_errno = TRY_AGAIN;
  105.                 break;
  106.             case NOERROR:
  107.                 h_errno = NO_DATA;
  108.                 break;
  109.             case FORMERR:
  110.             case NOTIMP:
  111.             case REFUSED:
  112.             default:
  113.                 h_errno = NO_RECOVERY;
  114.                 break;
  115.         }
  116.         return (-1);
  117.     }
  118.     return(n);
  119. }
  120.  
  121. /*
  122.  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  123.  * Return the size of the response on success, -1 on error.
  124.  * If enabled, implement search rules until answer or unrecoverable failure
  125.  * is detected.  Error number is left in h_errno.
  126.  * Only useful for queries in the same name hierarchy as the local host
  127.  * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
  128.  */
  129. res_search(name, class, type, answer, anslen)
  130.     char *name;        /* domain name */
  131.     int class, type;    /* class and type of query */
  132.     u_char *answer;        /* buffer to put answer */
  133.     int anslen;        /* size of answer */
  134. {
  135.     register char *cp, **domain;
  136.     int n, ret, got_nodata = 0;
  137.     char *hostalias();
  138.  
  139.     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  140.         return (-1);
  141.  
  142.     errno = 0;
  143.     h_errno = HOST_NOT_FOUND;        /* default, if we never query */
  144.     for (cp = name, n = 0; *cp; cp++)
  145.         if (*cp == '.')
  146.             n++;
  147.     if (n == 0 && (cp = hostalias(name)))
  148.         return (res_query(cp, class, type, answer, anslen));
  149.  
  150.     /*
  151.      * We do at least one level of search if
  152.      *    - there is no dot and RES_DEFNAME is set, or
  153.      *    - there is at least one dot, there is no trailing dot,
  154.      *      and RES_DNSRCH is set.
  155.      */
  156.     if ((n == 0 && _res.options & RES_DEFNAMES) ||
  157.        (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
  158.          for (domain = _res.dnsrch; *domain; domain++) {
  159.         ret = res_querydomain(name, *domain, class, type,
  160.             answer, anslen);
  161.         if (ret > 0)
  162.             return (ret);
  163.         /*
  164.          * If no server present, give up.
  165.          * If name isn't found in this domain,
  166.          * keep trying higher domains in the search list
  167.          * (if that's enabled).
  168.          * On a NO_DATA error, keep trying, otherwise
  169.          * a wildcard entry of another type could keep us
  170.          * from finding this entry higher in the domain.
  171.          * If we get some other error (negative answer or
  172.          * server failure), then stop searching up,
  173.          * but try the input name below in case it's fully-qualified.
  174.          */
  175.         if (errno == ECONNREFUSED) {
  176.             h_errno = TRY_AGAIN;
  177.             return (-1);
  178.         }
  179.         if (h_errno == NO_DATA)
  180.             got_nodata++;
  181.         if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
  182.             (_res.options & RES_DNSRCH) == 0)
  183.             break;
  184.     }
  185.     /*
  186.      * If the search/default failed, try the name as fully-qualified,
  187.      * but only if it contained at least one dot (even trailing).
  188.      * This is purely a heuristic; we assume that any reasonable query
  189.      * about a top-level domain (for servers, SOA, etc) will not use
  190.      * res_search.
  191.      */
  192.     if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
  193.         answer, anslen)) > 0)
  194.         return (ret);
  195.     if (got_nodata)
  196.         h_errno = NO_DATA;
  197.     return (-1);
  198. }
  199.  
  200. /*
  201.  * Perform a call on res_query on the concatenation of name and domain,
  202.  * removing a trailing dot from name if domain is NULL.
  203.  */
  204. res_querydomain(name, domain, class, type, answer, anslen)
  205.     char *name, *domain;
  206.     int class, type;    /* class and type of query */
  207.     u_char *answer;        /* buffer to put answer */
  208.     int anslen;        /* size of answer */
  209. {
  210.     char nbuf[2*MAXDNAME+2];
  211.     char *longname = nbuf;
  212.     int n;
  213.  
  214. #ifdef DEBUG
  215.     if (_res.options & RES_DEBUG)
  216.         if (domain == NULL)
  217.             printf("res_querydomain(%s, (null), %d, %d)\n",
  218.             name, class, type);
  219.         else printf("res_querydomain(%s, %s, %d, %d)\n",
  220.             name, domain, class, type);
  221. #endif
  222.     if (domain == NULL) {
  223.         /*
  224.          * Check for trailing '.';
  225.          * copy without '.' if present.
  226.          */
  227.         n = strlen(name) - 1;
  228.         if (name[n] == '.' && n < sizeof(nbuf) - 1) {
  229.             bcopy(name, nbuf, n);
  230.             nbuf[n] = '\0';
  231.         } else
  232.             longname = name;
  233.     } else
  234.         (void)sprintf(nbuf, "%.*s.%.*s",
  235.             MAXDNAME, name, MAXDNAME, domain);
  236.  
  237.     return (res_query(longname, class, type, answer, anslen));
  238. }
  239.  
  240. char *
  241. hostalias(name)
  242.     register char *name;
  243. {
  244.     register char *C1, *C2;
  245.     FILE *fp;
  246.     char *file, *getenv(), *strcpy(), *strncpy();
  247.     char buf[BUFSIZ];
  248.     static char abuf[MAXDNAME];
  249.  
  250.     file = getenv("HOSTALIASES");
  251.     if (file == NULL || (fp = fopen(file, "r")) == NULL)
  252.         return (NULL);
  253.     buf[sizeof(buf) - 1] = '\0';
  254.     while (fgets(buf, sizeof(buf), fp)) {
  255.         for (C1 = buf; *C1 && !isspace(*C1); ++C1);
  256.         if (!*C1)
  257.             break;
  258.         *C1 = '\0';
  259.         if (!strcasecmp(buf, name)) {
  260.             while (isspace(*++C1));
  261.             if (!*C1)
  262.                 break;
  263.             for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
  264.             abuf[sizeof(abuf) - 1] = *C2 = '\0';
  265.             (void)strncpy(abuf, C1, sizeof(abuf) - 1);
  266.             fclose(fp);
  267.             return (abuf);
  268.         }
  269.     }
  270.     fclose(fp);
  271.     return (NULL);
  272. }
  273.